package com.java.simple.smallspring.aop.support;

import cn.hutool.core.lang.Assert;
import cn.hutool.core.util.StrUtil;
import com.java.simple.smallspring.beans.factory.BeanFactory;
import com.java.simple.smallspring.beans.factory.BeanFactoryAware;
import lombok.Getter;
import lombok.Setter;
import org.aopalliance.aop.Advice;

import java.util.Objects;

/**
 * @author zhoujunlin
 * @date 2022年11月20日 12:54
 * @desc
 */
public abstract class AbstractBeanFactoryPointcutAdvisor extends AbstractPointcutAdvisor implements BeanFactoryAware {

    @Getter
    @Setter
    private String adviceBeanName;
    private BeanFactory beanFactory;
    private transient volatile Advice advice;
    private transient volatile Object adviceMonitor = new Object();

    public void setAdvice(Advice advice) {
        synchronized (this.adviceMonitor) {
            this.advice = advice;
        }
    }

    @Override
    public Advice getAdvice() {
        Advice advice = this.advice;
        if (Objects.nonNull(advice)) {
            return advice;
        }
        Assert.state(StrUtil.isNotBlank(this.adviceBeanName), "adviceBeanName must be specified");
        Assert.state(Objects.nonNull(this.beanFactory), "BeanFactory must be set to resolve adviceBeanName");
        advice = this.beanFactory.getBean(this.adviceBeanName, Advice.class);
        this.advice = advice;
        return advice;
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
        resetAdviceMonitor();
    }

    private void resetAdviceMonitor() {
        this.adviceMonitor = new Object();
    }
}
